<?php
/**
* urlFinder, where the magic happens
*
* arguably the most important file, the urlFinder class is passed the url sent
* to xdcms.  it then looks up and include the appropriate module.  it also displays 
* the module.  there are two methods, one for getting "normal" modules and one for 
* handling the ACP
*@author		wil hamilton <wil.hamilton@gmail.com>
*@license		bsd
*@version		0.5
*@package		core
* @todo 		finish commenting, better documentation; 
 */
 
class moduleLoader {

	
	/**
	*	given a url (actually $_SERVER['path_info'] it loads the proper module
	*
	*/
    final public static function getModule($url)
	{
		global $config;
		
		#get information on the proper url to lookup from the database
		$urlArray = self::extractUrl($url);
		
		# If there is a URL to look up ($urlArray['found'] == true) we look up the url in the database to get the method and module we should call
		# if there is not url to look up, but we should be grabbing the default module and method ($urlArray['default'] == true) then we grab that information from $config
		# if non of these are true we grab the 404 module (also found from the config)
		if($urlArray['found'])
		{
			# There is a URL to look up, so we look up the url to find the proper module and method to load
			$moduleQuery = new Query("SELECT * FROM `urls` WHERE `url` = '" . $urlArray['url'] . "' LIMIT 0, 1");
			
			$moduleQueryResult = $moduleQuery->fetch_assoc();
			
				$module = new module($moduleQueryResult['module']);
				$method = $moduleQueryResult['method'];
			
		}
		else if($urlArray['default'])
		{
			#load the  default module and method
			$module = new module($config['default-module-id']);
			$method = $config['default-module-method'];
		}
		else
		{
			#oh no, nothing has been found => 404
			$module = new module($config['404-module-id']);
			$method = '';
		}
		
		#based on the above module and method data, call the proper module and method
		self::loadModule($module, $method, $urlArray['vars']);
	}	
	
	final public function loadModule($module, $method, $vars)
	{
		//there are a couple of different ways a module can be structured, this function trys to load the module based on these structures and the information provided to  it
		if(file_exists(ROOT . 'modules/' . $module->location . '/controller.php'))
		{
			include(ROOT . 'modules/' . $module->location . '/controller.php');
			
			$controller = new Controller;
	
			//if a method is defined in the custom url use it, if not, look in the url for a method being called
			if($method != '')
			{
				define('CONTROLLER_METHOD', $method);
			}
			else
			{
				#if there is no method set in url vars, use the default method (generally index)
				if(empty($vars[0])) $vars[0] = $controller->method[0];
				
				#check to see if the method defined in the url exists, if not, use the default
				if(!method_exists($controller, $vars[0]))
				{
					array_unshift($vars, $controller->method[0]);
				}
				
				
				#define the method which will ge called
				define('CONTROLLER_METHOD',		array_shift($vars));
			}
			
			#actually call the method from the controller
			call_user_func_array(array(&$controller, CONTROLLER_METHOD), $vars);
			
			echo $controller;
		}
		elseif (file_exists(ROOT . 'modules/' . $module->location . '/' .  $vars[0] . '.php'))
		{
			include(ROOT . 'modules/' . $module->location . '/' .  $vars[0] . '.php');
		}
		else
		{
			include(ROOT . 'modules/' . $module->location . '/index.php');
		}
	}
	
	/**
	 * extract url is passed the path info $_SERVER var => $_SERVER['PATH_INFO']
	 * it then takes this and looks up whatever url it maps to, if no url is found, it sets whether it was not found, or whether we should use the defaults
	 */
	final public function extractUrl($url)
	{
		#set up our working var
		$actualUrl = '/';
		
		#set up our final vars
		$urlArray['url'] = '';
		$urlArray['vars'] = array();
		$urlArray['found'] = false;
		$urlArray['default'] = false;
		
		#transform the url from the server to an array of url parts
		$url = array_values(array_filter(explode('/', $url)));
		
		#if there are no url parts we say that we should load the default, if there are url parts, we try to look up the url
		if(count($url) == 0)
		{
			# There are no URL parts, so we say to use the default
			$urlArray['default'] = true;
		}
		else
		{
			# There are URL parts, so we loop through each one trying to build the final url that we should look up.  Any URL part that isn't a piece of the url stored in the 
			# database gets added to an array of URL variables which then gets passed to whatever module gets called.
			for($i = 0; $i< count($url);$i++)
			{
				$urlQuery = new Query("SELECT * FROM `urls` WHERE `url` LIKE '%" . $actualUrl . $url[$i] . "/%'");
				
				#if the number of rows returned by the query is greater than zero, then the current URL part is a piece of the final URL, so add it in, if it isn't we add it to the  URL vars
				if($urlQuery->num_rows())
				{
					# This piece of the url is a part of the final url so add it to the actual url
					# set the found variable true to denote if we should throw a 404 or not
					$actualUrl .= $url[$i] . '/';
					$urlArray['found'] = true;
				}
				else
				{
					#this part of the url is not a part of the final url, add it to the vars array
					if(!substr($actualUrl, -2, 1) == '*')
					{
						$actualUrl .= '*/';
					}
					$urlArray['vars'][] = $url[$i];
				}
				
			
			}
			if(strpos($actualUrl,  '*') === false)
			{
				$actualUrl .= '*';
			}
		}
		#if a url was found, pass it through via the $urlArray
		if($urlArray['found'])
		{
			$urlArray['url'] = '/'.implode('/',explode('/',trim($actualUrl, '/')));
		}
		
		return $urlArray;
	}
	
	/**
	 * gets the appropriate module from the url in the ACP
	 */
	final public static function getACP($urlParts)
	{
		if(file_exists(ROOT . 'modules/' . $urlParts[0] . '/admin.php'))
		{
			include(ROOT . 'modules/' . $urlParts[0] . '/admin.php');
			array_shift($urlParts);
			$urlVars = $urlParts;
		}
		else
		{
			echo 'Error 404';
		}
		
		$controller = new Controller;
		
		$controller->display = false;
			
		#if there is no method set in url vars, use the default method (generally index)
		if(empty($urlVars[0])) $urlVars[0] = $controller->method[0];
		
		#check to see if the method defined in the url exists, if not, use the default
		if(!method_exists($controller, $urlVars[0]))
		{
			array_unshift($urlVars, $controller->method[0]);
		}
		
		
		#define the method which will ge called
		define('CONTROLLER_METHOD',		array_shift($urlVars));
		
		#actually call the method from the controller
		call_user_func_array(array(&$controller, CONTROLLER_METHOD), $urlVars);
		
		
		echo $controller;
	}
	
	
}
 
?>